//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.goldhuman.Common;

import java.util.TimerTask;
import java.util.*;

public class Cache {
    public static int default_size = 100;
    public static int default_timeout = 10;
    private Map<Item, Item> cache = new HashMap();
    private LRU lru = new LRU();
    private int nitem;
    private int maxsize;
    private int time_stamp;
    private int life_time;
    private int[] key_pos;
    private static Map<String, Cache> all_caches = Collections.synchronizedMap(new HashMap());

    static {
        (new Timer(true)).schedule(new TimerTask() {
            public void run() {
                synchronized(Cache.all_caches) {
                    Iterator<Map.Entry<String, Cache>> i1 = Cache.all_caches.entrySet().iterator();

                    while(i1.hasNext()) {
                        Cache c = (Cache)((Map.Entry)i1.next()).getValue();
                        synchronized(c) {
                            Iterator<Map.Entry<Item, Item>> i2 = c.cache.entrySet().iterator();

                            while(i2.hasNext()) {
                                Item item = (Item)((Map.Entry)i2.next()).getValue();
                                int var10002 = item.life_time - 1;
                                item.life_time = var10002;
                                if (var10002 <= 0) {
                                    item.revoke();
                                    i2.remove();
                                    c.lru.remove(item);
                                }
                            }
                        }
                    }

                }
            }
        }, 0L, 1000L);
    }

    private void add(Item item) {
        item.life_time = this.life_time;
        if (this.cache.size() == this.maxsize) {
            this.remove(this.lru.last());
        }

        this.cache.put(item, item);
        this.lru.add(item);
    }

    private void remove(Item item) {
        item.revoke();
        this.cache.remove(item);
        this.lru.remove(item);
    }

    private boolean contains(Item item) {
        return this.cache.containsKey(item);
    }

    private Cache(int nitem, int[] key_pos) {
        this.maxsize = default_size;
        this.time_stamp = 0;
        this.life_time = default_timeout;
        this.nitem = nitem;
        this.key_pos = key_pos;
    }

    private Cache(int nitem, int[] key_pos, int maxsize, int life_time) {
        this.maxsize = default_size;
        this.time_stamp = 0;
        this.life_time = default_timeout;
        this.nitem = nitem;
        this.key_pos = key_pos;
        this.maxsize = maxsize;
        this.life_time = life_time;
    }

    public static Cache Create(String name, int nitem, int[] key_pos) {
        Cache c = new Cache(nitem, key_pos);
        all_caches.put(name, c);
        return c;
    }

    public static Cache Create(String name, int nitem, int[] key_pos, int maxsize, int life_time) {
        Cache c = new Cache(nitem, key_pos, maxsize, life_time);
        all_caches.put(name, c);
        return c;
    }

    public static Cache getInstance(String name) {
        return (Cache)all_caches.get(name);
    }

    public synchronized int size() {
        return this.cache.size();
    }

    public synchronized Item find(Item key_item) {
        Item item = (Item)this.cache.get(key_item);
        if (item == null) {
            return null;
        } else {
            this.lru.access(item);
            return (Item)item.clone();
        }
    }

    public Item newItem() {
        return new Item(this);
    }

    public static void main(String[] args) {
        Cache cache = Create("c1", 2, new int[1]);

        try {
            cache.newItem().set(0, new Integer(1)).set(1, new String("a")).commit();
            cache.newItem().set(0, new Integer(2)).set(1, new String("b")).commit();
            cache.newItem().set(0, new Integer(3)).set(1, new String("c")).commit();
            cache.newItem().set(0, new Integer(4)).set(1, new String("d")).commit();
            cache.newItem().set(0, new Integer(5)).set(1, new String("e")).commit();
            System.out.println("Size = " + cache.size());
            Thread.sleep(1000L);
            System.out.println("Size = " + cache.size());
            Thread.sleep(1000L);
            System.out.println("Size = " + cache.size());
            Thread.sleep(1000L);
            System.out.println("Size = " + cache.size());
            Thread.sleep(1000L);
            System.out.println("Size = " + cache.size());
            Thread.sleep(1000L);
            System.out.println("Size = " + cache.size());
        } catch (Exception var3) {
            var3.printStackTrace();
        }

    }

    public class Item implements Cloneable {
        private static final int CLEAN = 0;
        private static final int DIRTY = 1;
        private Item origin;
        private int time_stamp;
        private int life_time;
        private int access_count;
        private int status;
        private Object[] items;
        private Cache owner;

        protected Object clone() {
            try {
                Item item = (Item)super.clone();
                item.items = new Object[this.items.length];
                System.arraycopy(this.items, 0, item.items, 0, this.items.length);
                item.origin = this;
                return item;
            } catch (Exception var2) {
                return null;
            }
        }

        private Item(Cache owner) {
            this.access_count = 0;
            this.owner = owner;
            this.items = new Object[owner.nitem];
            this.status = 1;
            int var10003 = owner.time_stamp;
            owner.time_stamp = var10003 + 1;
            this.time_stamp = var10003;
        }

        private void revoke() {
        }

        public boolean equals(Object obj) {
            for(int i = 0; i < this.owner.key_pos.length; ++i) {
                if (!this.items[Cache.this.key_pos[i]].equals(((Item)obj).items[Cache.this.key_pos[i]])) {
                    return false;
                }
            }

            return true;
        }

        public int hashCode() {
            int hash = 0;

            for(int i = 0; i < this.owner.key_pos.length; ++i) {
                hash = hash + this.items[Cache.this.key_pos[i]].hashCode() * 17 >> 4;
            }

            return hash;
        }

        public void commit() throws RuntimeException {
            if (this.status != 0) {
                synchronized(this.owner) {
                    if (this.origin == null) {
                        if (this.owner.contains(this)) {
                            throw new RuntimeException("Duplicate Key");
                        }
                    } else {
                        if (this.origin.time_stamp != this.time_stamp) {
                            throw new RuntimeException("TimeStamp Collision");
                        }

                        if (this.hashCode() != this.origin.hashCode() || !this.equals(this.origin)) {
                            this.owner.remove(this.origin);
                        }

                        Item var10001 = this.origin;
                        Cache var10002 = this.owner;
                        int var10004 = var10002.time_stamp;
                        var10002.time_stamp = var10004 + 1;
                        this.time_stamp = var10001.time_stamp = var10004;
                        this.origin = null;
                    }

                    this.status = 0;
                    this.owner.add(this);
                }
            }
        }

        public Item set(int pos, Object obj) {
            this.items[pos] = obj;
            this.status = 1;
            return this;
        }

        public Object get(int pos) {
            return this.items[pos];
        }
    }

    private class LRU {
        private TreeMap<Integer, LinkedList<Item>> lru;

        private LRU() {
            this.lru = new TreeMap();
        }

        public void add(Item item) {
            Integer ac = new Integer(item.access_count);
            LinkedList<Item> ll = (LinkedList)this.lru.get(ac);
            if (ll == null) {
                this.lru.put(ac, ll = new LinkedList());
            }

            ll.addLast(item);
        }

        public void remove(Item item) {
            Integer ac = new Integer(item.access_count);
            LinkedList<Item> ll = (LinkedList)this.lru.get(ac);
            ll.remove(item);
            if (ll.size() == 0) {
                this.lru.remove(ac);
            }

        }

        public Item last() {
            return (Item)((LinkedList)this.lru.get(this.lru.firstKey())).getFirst();
        }

        public void access(Item item) {
            this.remove(item);
            item.access_count = item.access_count + 1;
            this.add(item);
        }
    }
}
